import { INestApplicationContext, WebSocketAdapter } from '@nestjs/common'
import { MessageMappingProperties } from '@nestjs/websockets'
import { EMPTY, Observable, fromEvent } from 'rxjs'
import { filter, mergeMap } from 'rxjs/operators'
import * as WebSocket from 'ws'

export class WsAdapter implements WebSocketAdapter {
  constructor(private app: INestApplicationContext) { }

  public clientsOnline: Array<WebSocket> = [];
  create(port: number, options: any = {}): any {
    console.log('ws create')
    return new WebSocket.Server({ port, ...options })
  }

  // eslint-disable-next-line @typescript-eslint/ban-types
  bindClientConnect(server, callback: Function) {
    console.log('ws bindClientConnect, server:\n')
    server.on('connection', callback)

    server.on('close', callback)
  }

  xx(client) {
    console.log('断开')

    this.clientsOnline.forEach((item, index) => {
      if (client === item) {
        this.clientsOnline.splice(index, 1)
      }
    })

  }

  bindClientDisconnect(client: any, callback: Function) {
    client.on('close', this.xx.bind(this, client))
  }

  bindMessageHandlers(
    client: WebSocket,
    handlers: MessageMappingProperties[],
    process: (data: any) => Observable<any>,
  ) {
    console.log('[waAdapter]有新的连接进来')
    this.clientsOnline.push(client)
    console.log(this.clientsOnline.length)

    fromEvent(client, 'message')
      .pipe(
        mergeMap((data) =>
          this.bindMessageHandler(client, data, handlers, process),
        ),
        filter((result) => result),
      )
      .subscribe((response) => client.send(JSON.stringify(response)))
  }

  bindMessageHandler(
    client: WebSocket,
    buffer,
    handlers: MessageMappingProperties[],
    process: (data: any) => Observable<any>,
  ): Observable<any> {
    let message = null
    try {
      message = JSON.parse(buffer.data)
      console.log('消息类型：', message.type || '空')
      console.log('接收消息：', message)
      // 给所有客户端发消息
      if (message.type !== 'heartBeat') {
        console.log(2)

        this.clientsOnline.forEach((item) => {
          if (item) {
            item.send(JSON.stringify(message))
          }
        })
      }
    } catch (error) {
      console.log('ws解析json出错', error)
      return EMPTY
    }

    const messageHandler = handlers.find(
      (handler) => handler.message === message.event,
    )
    if (!messageHandler) {
      return EMPTY
    }
    return process(messageHandler.callback(message.data))
  }

  close(server) {
    console.log('ws server close')
    // this.clientsOnline.
    server.close()
  }
}
